package com.romotc.qqrobot.webqq.qqInterfaceCatching;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.romotc.scache.RequestSpy;
import com.romotc.scache.WebConnection;
import com.romotc.scache.cacheobject;
import com.romotc.scache.mgr;
import com.romotc.scache.request;

/**
 * 拦截请求并返回指定内容(body)的基础类
 * @author Administrator
 *
 */
public abstract class QQUrlBodyCatching extends QQUrlCatchingInterface {

	/**
	 * 拦截请求 并返回指定内容
	 * @return null 请求将继续调用；如果返回非null则根据isGoOn决定是否继续请求
	 */
	abstract String getHackReqBodyStr(RequestSpy requestSpy, Map<String, Object> var) ;
	
	/**
	 * 是否继续请求
	 * @return
	 */
	abstract boolean isGoOn(RequestSpy requestSpy);
	
	 
	abstract ArrayList<String> hackRequestHeader(RequestSpy requestSpy, int bodySize, Map<String, Object> var) ;
	
	/**
	 * 检查拦截条件
	 * @param requestSpy
	 * @return true:符合条件；false 不符合条件
	 */
	public boolean checkChatchingCondition(RequestSpy requestSpy) {
		return true;
	}
	
	@Override
	public boolean hackRequest(RequestSpy requestSpy) {
		
		HashMap<String, Object> var = new HashMap<String, Object>();
		
		
		String retStr = null;
		
		if(checkChatchingCondition(requestSpy))
			retStr = getHackReqBodyStr(requestSpy, var);
		
		if(retStr == null)
			return true;
		else {//不需要继续执行则读取输入流
			//先读浏览器的输入流 一边request.requestBody信息能够获取到
			requestSpy.readRequestInfo();
		}
		
		byte[] b;
		try {
			b = retStr.getBytes("utf-8");
			
			ByteArrayInputStream bis = new ByteArrayInputStream(b);
			DataInputStream dis = new DataInputStream(bis);
			
			requestSpy.make_headers(200, null, null, null, b.length, new Date()
			.getTime(), 0, null);
			
			ArrayList<String>  headers = hackRequestHeader(requestSpy, b.length, var);
			if(headers != null) {
				requestSpy.headers = headers;
			}
			
			requestSpy.ctsize = b.length;
			
			readHeaders(requestSpy.headers, requestSpy);
			
			requestSpy.send_headers();
			WebConnection wc = new WebConnection(dis);
			requestSpy.transfer_object(wc, null, null);
			
			return isGoOn(requestSpy);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return true;
	}
	

	private static void readHeaders(List<String> headers, request request) {

		int i = 0;
		request.ims = 0; /* pro last modified */
		request.exp = 0;
		request.ctsize = -1;
		request.encoding = null;
		request.etag = null;
		request.location = null;
		request.ctype = "text/html"; // like Mozilla does
		request.reload = false; /* pouzivano pro pragma: no-cache */
		request.chunked = false;
		int pnci = -1;
		int expi = -1;
		int cci = -1;
		for(String header : headers) {
			int j;
			String s1, s2;
			if (request.trace_reply)
				System.out.println("[TRACE " + Thread.currentThread().getName()
						+ "] < " + header);
			j = header.indexOf(':', 0);
			if (j == -1)
				continue;
			s1 = header.substring(0, j).toLowerCase();
			s2 = header.substring(j + 1).trim();

			
			if (s1.equals("pragma")) {
				request.reload = true;
				/* pnc is last hdr for now, adding more hdr later */
				pnci = i;
				continue;
			}
			if (s1.equals("cache-control")) {
				s2 = s2.toLowerCase();
				if (s2.indexOf("private") > -1) {
					if (request.cacheable)
						request.cacheable = request.cache_private;
					continue;
				}
				if (s2.indexOf("no-") > -1) {
					request.reload = true;
					cci = i;
					continue;
				}
			}
			if (s1.equals("vary")) {
				if (request.cacheable)
					request.cacheable = request.cache_vary;
				continue;
			}
			if (s1.equals("content-length")) {
				try {
					request.ctsize = Integer.valueOf(s2).intValue();
				} catch (Exception ignore) {
				}
				continue;
			}
			if (s1.equals("content-type")) {
				request.ctype = s2;
				continue;
			}
			if (s1.equals("content-encoding")) {
				request.encoding = s2;
				continue;
			}
			if (s1.equals("transfer-encoding")) {
				if (s2.equalsIgnoreCase("chunked")) {
					request.chunked = true;
//					headers.remove(i--);
				}
				continue;
			}
			if (s1.equals("connection") || s1.equals("proxy-connection")) {
				if (s2.length() == 5)
//					wc.keepalive = false;
//				else
//					wc.keepalive = true;
//				headers.remove(i--);
				continue;
			}
			if (s1.equals("etag")) {
				request.etag = s2;
				continue;
			}
			if (s1.equals("location")) {
				request.location = s2;
				continue;
			}

			if (s1.equals("last-modified")) {
				try {
					request.ims = new Date(s2).getTime();
				} catch (IllegalArgumentException e) {
					request.ims = 0;
				}
				continue;
			}

			if (s1.equals("expires")) {
				try {
					request.exp = new Date(s2).getTime();
					if (request.exp == 0)
						throw new IllegalArgumentException("Forced parse error");
				} catch (IllegalArgumentException e) {
					/* Expires: never */
					if (s2.length() != 5) {
						/*
						 * we cant parse expire date and its not Expire: never
						 * mark object as allready expired
						 */
						request.exp = cacheobject.VINTAGE_DATE;
					} else {
						request.exp = 0;
					}
				} finally {
					expi = i;
				}
				continue;
			}
			if (mgr.allow_cookies_to != null && request.allow_all_session_cookies
					&& s1.equals("set-cookie")) {
				s2 = header.toLowerCase();
				/* is this a permanent cookie? */
				if (s2.indexOf("expires") != -1 || s2.indexOf("max-age") != -1) {
					boolean allowed = false;
					/* needs to scan */
					for (int k = mgr.allow_cookies_to.length - 1; k >= 0; k--)
						if (request.hostname.endsWith(mgr.allow_cookies_to[k])) {
							allowed = true;
							break;
						}

					if (!allowed) {
						/* replace cookie content */
						StringBuffer newCook = new StringBuffer(header);
						if (request.trace_cookie)
							System.out.println("[TRACE "
									+ Thread.currentThread().getName()
									+ "] @ Unallowed persistent cookie "
									+ newCook + " from " + request.hostname);

						int ei = 0;
						/* remove expires from reply */
						while (true) {
							ei = s2.indexOf("expires", ei);
							if (ei > -1) {
								newCook.setCharAt(ei, 'X');
								ei++;
							} else
								break;
						}

						ei = 0;

						/* remove max-age from reply */
						while (true) {
							ei = s2.indexOf("max-age", ei);
							if (ei > -1) {
								newCook.setCharAt(ei, 'X');
								ei++;
							} else
								break;
						}

						headers.set(i, newCook.toString());
					}
				}
			}

		}
		
	}

}
